package bch.netty;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.nio.NioEventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;


/**
 * @author DCJ
 * <p>
 * Raw  -- ws://192.168.1.87:2469/ws
 *
 *
 * {@link NioEventLoop#run()} 为什么不会一直循环?
 *
 * {@link ServerBootstrap#init(Channel)}
 *      配置 ServerChannel 的 pipeline
 *          如果你 .handler(new LoggingHandler()) → 这个 handler 会在 ServerChannel 上生效
 *          也就是你之前问的 handlerAdded() 在服务端启动时触发的来源
 *      安装 ServerBootstrapAcceptor
 *          创建一个 NioSocketChannel
 *          给它的 pipeline 加上你配置的 .childHandler(...)
 *          设置 .childOption(...) 和 .childAttr(...)。
 *          把这个子 channel 注册到 workerGroup
 *      保存 child 配置
 *          .childHandler() / .childOption() / .childAttr() 这些都会被保存，等有新连接时由 ServerBootstrapAcceptor 应用
 */
@Component
@Slf4j
public class WebSocketServer implements CommandLineRunner {

    @Value("${server.port:2369}")
    private int port;

    @Resource
    private WebSocketServerChannelInitializer webSocketServerChannelInitializer;

    public void init() throws InterruptedException {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            serverBootstrap

                    // 指定单线程 多线程 主从架构
                    .group(bossGroup, workerGroup)
                    // 隐式添加了acceptor
                    /**
                     * {@link ServerBootstrap.ServerBootstrapAcceptor#channelRead(ChannelHandlerContext, Object)} : 当 BossGroup 接收到新连接时，完成子 Channel 的初始化（pipeline、options、attrs），然后把它安全地注册到 WorkerGroup，让它接管后续 I/O
                     *
                     */
                    .handler(new LoggingHandler("BossLoggingHandler", LogLevel.INFO))

                    .channel(NioServerSocketChannel.class)

                    .childHandler(webSocketServerChannelInitializer);

            // 同步等待异步请求的结果, 等待bind结果
            ChannelFuture channelFuture = serverBootstrap.bind(new InetSocketAddress(port + 100)).sync();

            // 同步等待channel关闭
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }


    @Override
    public void run(String... args) throws Exception {
        init();
    }
}